#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>

#include "IOperator.h"
#include "OperatorAdd.h"
#include "OperatorSubstract.h"
#include "OperatorMultiply.h"
#include "OperatorDivide.h"
#include "OperatorPower.h"
#include "Operation.h"

using namespace std;

void show_help(unsigned int nb_operators, IOperator* list_operator[])
{
  cout << endl;
  cout << "  *** Welcome to basic calculator ***" << endl;
  cout << endl;
  cout << "  Enter an operation as :" << endl;
  cout << "  <left_value> <operator> <right_value>" << endl;
  cout << "  You can select all value you want," << endl;
  cout << "  but only those operator are available :" << endl;
  for (unsigned int i=0; i<nb_operators; ++i) cout << "  " << list_operator[i]->str();
  cout << endl;
  cout << "  Type \"quit\" or \"q\" to exit the program" << endl;
  cout << endl;
}

int main(int argc, const char* argv[])
{
    // definition of different strategies
    const unsigned int nb_operators = 5;
    IOperator* list_operator[nb_operators] = { new OperatorAdd, new OperatorSubstract, new OperatorMultiply, new OperatorDivide, new OperatorPower };

    show_help(nb_operators, list_operator);

    // definition of the context
    Operation current_operation;

    // temporary variables
    double l_value = 0., r_value = 0.;
    bool quit = false;
    string tmp = "";

    // loop on user operations
    while ( ! quit )
    {
        current_operation.set_operator(NULL);
        cout << "> ";

        getline(cin,tmp);

        // test if exit the program
        if ( strcmp(tmp.c_str(), "quit") == 0 || strcmp(tmp.c_str(), "q") == 0 )
            quit = true;

        // research the operator
        else if ( strcmp(tmp.c_str(), "") != 0 )
        {
            // search in operator
            for (unsigned int i=0; i<nb_operators; ++i)
            {
                if ( tmp.find( list_operator[i]->str() ) != string::npos )
                {
                    current_operation.set_operator( list_operator[i] );
                    break;
                }
            }

            // definition of the strategy (if one is found)
            if ( current_operation.get_operator() != NULL )
            {
                // reading left and rigth value
                l_value = atof( tmp.substr( 0, tmp.find( current_operation.get_operator()->str() ) ).c_str() );
                r_value = atof( tmp.substr( tmp.find( current_operation.get_operator()->str() ) + 1).c_str() );

                // execution of the algoritm of the strategy
                cout << current_operation.execute(l_value, r_value) << endl;
            }

            // if the operator is not found
            else
            {
                cout << "????" << endl;
            }
        }
    } // end while(!quit)

    return EXIT_SUCCESS;
}
